/**
 * 
 */

/** Constants */
var WINDOW_WIDTH=400;
var WINDOW_HEIGHT=400;

var minX=-WINDOW_WIDTH/2;
var minY=-WINDOW_HEIGHT/2;
var maxX=-minX;
var maxY=-minY;
/** class Function */
function Function2D(){
	this.nextY= function(x){
		return Math.sin(x);
	}
}
/** class Point */
function Point(x,y){
	this.x=x;
	this.y=y;
}

/** Function Processor */
function FunctionProcessor(increment, function2D,scaleX,scaleY){
	this.increment=increment;
	this.function2D=function2D;
	this.scaleX=scaleX;
	this.scaleY=scaleY;
	
	
	this.getGraph= function(){
		var points=new Array();
		
		for(x=minX;x<maxX;x=x+this.increment){
			
			var sx=scaleX*x;
			var y=function2D.nextY(sx);
			var point=new Point(sx,y);
			if(!isNaN(y)&&this.isWithinBound(point)){
				points.push(point);
			}
		}
		
		//last point
		var sx=this.maxX*this.scaleX;
		var y=function2D.nextY(sx);
		var point=new Point(sx,y);
		if(!isNaN(y)&&this.isWithinBound(point)){
			points.push(point);
		}
		return points;
	}
	
	this.isWithinBound=function(point){
		return (point.x>=minX&&point.x<=maxX&&point.y>=minY&&point.y<=maxY)
	}
	
	this.getMinY= function(){
		var points=this.getGraph();
		if(points.length==0){
			return 0;
		}
		var y=points[0].y;
		for(i=1;i<points.length;i++){
			if(y>points[i].y){
				y=points[i].y;
			}
		}
		
		return y;
	}
	
	this.getMaxY= function(){
		var points=this.getGraph();
		if(points.length==0){
			return 0;
		}
		var y=points[0].y;
		for(i=1;i<points.length;i++){
			if(y<points[i].y){
				y=points[i].y;
			}
		}
		return y;
	}
	
	this.disY=function(){
		return this.getMaxY()-this.getMinY();
	}
	
	this.getScaleY=function(){
		var disY=this.disY();
		var sy=1;
		if(disY!=0){
			sy=WINDOW_HEIGHT/disY;
		}
		var ay=Math.abs(sy)*this.scaleY;
		return ay;
	}
	
	this.getScaleX=function(){
		return this.scaleX;
	}
	
}
/** Util */
function Util(){
	this.toGraphPoint=function(p,scaleX,scaleY){
		var point=new Point();
		point.x=p.x/scaleX+WINDOW_WIDTH/2;
		point.y=-p.y*scaleY+WINDOW_HEIGHT/2;
		return point;
	}
	
	this.toMathPoint=function(p,scaleX,scaleY){
		var point=new Point();
		point.x=(p.x-WINDOW_WIDTH/2)*scaleX;
		point.y=(-p.y+WINDOW_HEIGHT/2)/scaleY;
		return point;
	}
}


// graphics


/**
 * use processing js
 */


function drawingWork(scaleX, scaleY) {


	// function
	var function2D = new Function2D();
	var functionProcessor = new FunctionProcessor(0.1, function2D, scaleX, scaleY);
	var util= new Util(); 
	
	this.drawer = function(processing) {
		
		// do all drawing here
		processing.setup = function() {
			processing.size(WINDOW_WIDTH, WINDOW_HEIGHT);
			processing.strokeWeight(2);
			processing.smooth();
			processing.frameRate(15);

		}

		processing.draw = function() {

			processing.background(100);
			drawAxis();
			var points = functionProcessor.getGraph();
			processing.strokeWeight(1);
			var scaleY = functionProcessor.getScaleY();
			var scaleX = functionProcessor.getScaleX();
			for ( i = 0; i < points.length - 1; i++) {
				var p1 = points[i];
				var p2 = points[i + 1];
				drawLine(p1, p2, scaleX, scaleY);

			}
			
			// draw mouse position
			var mouseP=new Point(processing.mouseX,processing.mouseY);
			var mathPoint=util.toMathPoint(mouseP, scaleX, scaleY);
			var x=mathPoint.x;
			var y=mathPoint.y;
			processing.text("(x="+x+","+"y="+y.toFixed(1)+")",processing.mouseX,processing.mouseY);
		}
		
		function drawLine(p1, p2,  scaleX,  scaleY) {

			var g1 = util.toGraphPoint(p1, scaleX, scaleY);
			var g2 = util.toGraphPoint(p2, scaleX, scaleY);
			processing.line(g1.x, g1.y, g2.x, g2.y);

		}
		function drawAxis(){
			processing.strokeWeight(1);
			// x axis
			drawArrow(new Point(minX, 0), new Point(
					maxX, 0));

			var scaleX = functionProcessor.getScaleX();
			for ( x = minX; x <= maxX; x = x + 100) {
				var p = new Point(x, 0);
				drawNodeX(p, x * scaleX);
			}

			// y axis
			drawArrow(new Point(0, minY), new Point(0,
					maxY));

			var scaleY = functionProcessor.getScaleY();
			for ( y = minY; y <= maxY; y = y + 100) {
				var p = new Point(0, y);
				if ( y != 0) {
					drawNodeY(p, y / scaleY);
				}
			}

		}
		
		function drawNodeX( p,  num) {

			var g1 = util.toGraphPoint(new Point(p.x, p.y + 10),1,1);
			var g2 = util.toGraphPoint(new Point(p.x, p.y - 10),1,1);
			processing.line(g1.x, g1.y, g2.x, g2.y);
			var text = util.toGraphPoint(new Point(p.x + 5, p.y - 20),1,1);
			
			processing.text(num, text.x, text.y);
		}

		function drawNodeY( p,  num) {

			var g1 = util.toGraphPoint(new Point(p.x - 10, p.y),1,1);
			var g2 = util.toGraphPoint(new Point(p.x + 10, p.y),1,1);
			processing.line(g1.x, g1.y, g2.x, g2.y);
			var text = util.toGraphPoint(new Point(p.x + 10, p.y + 10),1,1);
			
			processing.text(num.toFixed(1), text.x, text.y);
		}

		// draw an arrow
		function arrow( x1,  y1,  x2,  y2) {
			processing.line(x1, y1, x2, y2);
			processing.pushMatrix();
			processing.translate(x2, y2);
			var a = processing.atan2(x1 - x2, y2 - y1);
			 processing.rotate(a);
			 processing.line(0, 0, -10, -10);
			 processing.line(0, 0, 10, -10);
			 processing.popMatrix();
		}

		function drawArrow( p1,  p2) {
			var g1 = util.toGraphPoint(p1,1,1);
			var g2 = util.toGraphPoint(p2,1,1);
			arrow(g1.x, g1.y, g2.x, g2.y);
		}
		

		
	}

	// attach to canvas
	var canvas = document.getElementById("canvas");
	
	// attaching the drawing function to the canvas
	var p = new Processing(canvas, drawer);
}


	